import { Injectable, Logger } from '@nestjs/common';
import { Browser } from 'puppeteer';
import puppeteer from 'puppeteer-extra';
import { PlatformWithCookies, TaskWithPlatforms } from 'src/types';
import { PrismaService } from 'src/database/prisma.service';
import { JDScraper } from '../scrapers/jd/jd';
import TaoBaoScraper from '../scrapers/taobao/taobao';
import { Scraper } from 'src/scrapers/scraper';
import { PuppeteerDto } from './dto/puppeteer.dto';
import { HttpException, HttpStatus } from '@nestjs/common';
import { TaskStatus } from 'src/prisma/client';
@Injectable()
export class TaskService {
  constructor(private readonly prismaServer: PrismaService) {}

  async performWebScraping(url: string) {
    let browser: Browser = await puppeteer.launch({ headless: true });
    const page = await browser.newPage();
    Logger.debug('start scraping');
    await page.goto('https://search.jd.com');
    const value = await page.$eval('input.input_submit', (el) =>
      el.getAttribute('value'),
    );
    Logger.debug(`get value ${value}`);
    await page.close();
    await browser.close();
    Logger.debug('end scraping');
  }
  async scrap(pteDto: PuppeteerDto): Promise<string> {
    Logger.log(`scraping ${pteDto.selector},${pteDto.url}`);
    const scraper = new Scraper({
      url: pteDto.url,
      selector: pteDto.selector,
      keyword: '',
    });
    const result = (await scraper.rowScrap()) || 'None for scrap';
    Logger.warn(`scrap result:${result}`);
    return result;
  }
  async performScraping(task: TaskWithPlatforms) {
    await this.prismaServer.task.update({
      where: { id: task.id },
      data: {
        status: TaskStatus.RUNNING,
      },
    });
    try {
      Logger.log(`Performing task ${task.id} ${task.name} ${task.keyword} `);
      task.platforms.forEach((v: PlatformWithCookies) => {
        Logger.log(`platform ${v.name}`);
        let scraper: Scraper;
        if (v.name === '京东') {
          scraper = new JDScraper({
            taskId: task.id,
            url: v.url,
            keyword: task.keyword,
            cookie: v.cookies[0].content.toString(),
            dbService: this.prismaServer,
          });

          scraper
            .scraping()
            .catch((err) => {
              Logger.error(err);
            })
            .finally(() => {
              scraper.exit();
              this.prismaServer.task.update({
                where: { id: task.id },
                data: {
                  status: TaskStatus.COMPLETE,
                },
              });
            });
        } else if (v.name === '淘宝') {
          scraper = new TaoBaoScraper({
            taskId: task.id,
            url: v.url,
            keyword: task.keyword,
            cookie: v.cookies[0].content.toString(),
            dbService: this.prismaServer,
          });
          scraper
            .scraping()
            .catch((err) => {
              Logger.error(err);
            })
            .finally(() => {
              scraper.exit();
              this.prismaServer.task.update({
                where: { id: task.id },
                data: {
                  status: TaskStatus.COMPLETE,
                },
              });
            });
        }
      });
    } catch (error) {
      await this.prismaServer.task.update({
        where: { id: task.id },
        data: {
          status: TaskStatus.COMPLETE,
        },
      });
      Logger.error(error);
    }
  }
  async pagination(page: number, size: number, userId: number) {
    Logger.log(`pagination search size:${page},size:${size}`);
    const [total, tasks] = await this.prismaServer.$transaction([
      this.prismaServer.task.count({ where: { userId: userId } }),
      this.prismaServer.task.findMany({
        where: {
          userId: userId,
        },
        skip: size * page,
        take: size,
      }),
    ]);
    return { total, tasks };
  }
  async removePlatformFromTask(taskId: number, platId: number) {
    const result = await this.prismaServer.$transaction(async (prisma) => {
      const task = await prisma.task.findUnique({ where: { id: taskId } });
      if (!task)
        throw new HttpException(
          `Task ${taskId} not found`,
          HttpStatus.NOT_FOUND,
        );
      const platform = await prisma.platform.findUnique({
        where: { id: platId },
      });
      if (!platform)
        throw new HttpException(
          `Platform ${platId} not found`,
          HttpStatus.NOT_FOUND,
        );
      const deleted = await prisma.taskPlatform.deleteMany({
        where: { taskId, platformId: platId },
      });
      if (deleted.count === 0) {
        throw new HttpException(
          `Platform ${platId} not associated with Task ${taskId}`,
          HttpStatus.BAD_REQUEST,
        );
      }
      return { taskId, platId };
    });
    return {
      message: `Platform ${platId} removed from Task ${taskId}`,
      data: result,
    };
  }
  async list() {
    Logger.log(`get all tasks`);
    return await this.prismaServer.task.findMany({});
  }
}
